home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / termsorc.lha / Extras / Source / term-source.lha / termMsgQueue.c < prev    next >
C/C++ Source or Header  |  1995-09-26  |  7KB  |  398 lines

  1. /*
  2. **    termMsgQueue.c
  3. **
  4. **    Special MsgPort like queue management
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* DestroyPooled(struct MsgItem *Item):
  13.      *
  14.      *    Default destructor for CreateMsgItem().
  15.      */
  16.  
  17. STATIC VOID __stdargs
  18. DestroyPooled(struct MsgItem *Item)
  19. {
  20.     FreeVecPooled(Item);
  21. }
  22.  
  23.     /* GetMsgItem(struct MsgQueue *Queue):
  24.      *
  25.      *    Get the next message from the queue handle,
  26.      *    similar to GetMsg().
  27.      */
  28.  
  29. APTR __regargs
  30. GetMsgItem(struct MsgQueue *Queue)
  31. {
  32.         // Valid handle?
  33.  
  34.     if(Queue)
  35.     {
  36.         APTR Item;
  37.  
  38.             // Gain access
  39.  
  40.         ObtainSemaphore(&Queue -> Access);
  41.  
  42.             // Any item available?
  43.  
  44.         if(Queue -> MsgList . mlh_Head -> mln_Succ)
  45.         {
  46.                 // Remove the first item
  47.  
  48.             Remove((struct Node *)(Item = Queue -> MsgList . mlh_Head));
  49.  
  50.                 // Are there any tasks waiting for the queue to become smaller?
  51.  
  52.             if(Queue -> WaitList . mlh_Head -> mln_Succ)
  53.             {
  54.                 struct SemaphoreRequest *WaitRequest = (struct SemaphoreRequest *)Queue -> WaitList . mlh_Head;
  55.  
  56.                     // Remove one waiting task from the list
  57.  
  58.                 Remove((struct Node *)WaitRequest);
  59.  
  60.                     // Wake the task up
  61.  
  62.                 Signal(WaitRequest -> sr_Waiter,SIGF_SINGLE);
  63.             }
  64.  
  65.                 // One message taken
  66.  
  67.             if(Queue -> QueueSize)
  68.                 Queue -> QueueSize--;
  69.         }
  70.         else
  71.             Item = NULL;
  72.  
  73.             // Drop the semaphore
  74.  
  75.         ReleaseSemaphore(&Queue -> Access);
  76.  
  77.             // Return the item read
  78.  
  79.         return(Item);
  80.     }
  81.     else
  82.         return(NULL);
  83. }
  84.  
  85.     /* PutMsgItem(struct MsgQueue *Queue,struct MsgItem *Item):
  86.      *
  87.      *    Add a message item to a queue handle, similar to
  88.      *    PutMsg().
  89.      */
  90.  
  91. VOID __regargs
  92. PutMsgItem(struct MsgQueue *Queue,struct MsgItem *Item)
  93. {
  94.         // Valid data?
  95.  
  96.     if(Queue && Item)
  97.     {
  98.             // Gain access to the handle
  99.  
  100.         ObtainSemaphore(&Queue -> Access);
  101.  
  102.             // Are we to discard this message?
  103.  
  104.         if(Queue -> Discard)
  105.         {
  106.             ReleaseSemaphore(&Queue -> Access);
  107.  
  108.             DeleteMsgItem(Item);
  109.         }
  110.         else
  111.         {
  112.                 // Are we to watch for a maximum queue size?
  113.  
  114.             if(Queue -> MaxSize)
  115.             {
  116.                     // Maximum queue size already reached?
  117.  
  118.                 if(Queue -> MaxSize == Queue -> QueueSize)
  119.                 {
  120.                     struct SemaphoreRequest WaitRequest;
  121.  
  122.                         // That's me
  123.  
  124.                     WaitRequest . sr_Waiter = FindTask(NULL);
  125.  
  126.                         // Add this task to the waiting list
  127.  
  128.                     AddTail((struct List *)&Queue -> WaitList,(struct Node *)&WaitRequest);
  129.  
  130.                         // Careful, please
  131.  
  132.                     Forbid();
  133.  
  134.                         // Drop the semaphore
  135.  
  136.                     ReleaseSemaphore(&Queue -> Access);
  137.  
  138.                         // Clear the one-shot flag
  139.  
  140.                     ClrSignal(SIGF_SINGLE);
  141.  
  142.                         // Wait for the queue to become smaller
  143.  
  144.                     Wait(SIGF_SINGLE);
  145.  
  146.                         // Gain access to the handle
  147.  
  148.                     ObtainSemaphore(&Queue -> Access);
  149.  
  150.                         // Reenable multitasking
  151.  
  152.                     Permit();
  153.                 }
  154.  
  155.                     // We are going to make the queue longer
  156.  
  157.                 Queue -> QueueSize++;
  158.             }
  159.  
  160.                 // Add the item to the list
  161.  
  162.             AddTail((struct List *)&Queue -> MsgList,(struct Node *)Item);
  163.  
  164.                 // Wake up the owner
  165.  
  166.             Signal(Queue -> SigTask,Queue -> SigMask);
  167.  
  168.                 // Drop the semaphore
  169.  
  170.             ReleaseSemaphore(&Queue -> Access);
  171.         }
  172.     }
  173. }
  174.  
  175.     /* DeleteMsgItem(struct MsgItem *Item):
  176.      *
  177.      *    Clean up after a message item.
  178.      */
  179.  
  180. VOID __regargs
  181. DeleteMsgItem(struct MsgItem *Item)
  182. {
  183.         // Valid data?
  184.  
  185.     if(Item)
  186.     {
  187.             // Do we have a destructor for this item?
  188.  
  189.         if(Item -> Destructor)
  190.             (*Item -> Destructor)(Item);
  191.     }
  192. }
  193.  
  194.     /* CreateMsgItem(LONG Size):
  195.      *
  196.      *    Allocate a new message item.
  197.      */
  198.  
  199. struct MsgItem * __regargs
  200. CreateMsgItem(LONG Size)
  201. {
  202.     struct MsgItem    *Item;
  203.  
  204.         // Allocate space for the item and add the default destructor
  205.  
  206.     if(Item = (struct MsgItem *)AllocVecPooled(Size,MEMF_ANY))
  207.         Item -> Destructor = DestroyPooled;
  208.  
  209.     return(Item);
  210. }
  211.  
  212.     /* CreateMinMsgItem(LONG Size):
  213.      *
  214.      *    Allocate a new message item, make sure that the header
  215.      *    is present.
  216.      */
  217.  
  218. struct MsgItem * __regargs
  219. CreateMinMsgItem(LONG Size)
  220. {
  221.     struct MsgItem    *Item;
  222.  
  223.         // Allocate space for the item and add the default destructor
  224.  
  225.     if(Item = (struct MsgItem *)AllocVecPooled(sizeof(struct MsgItem) + Size,MEMF_ANY))
  226.         Item -> Destructor = DestroyPooled;
  227.  
  228.     return(Item);
  229. }
  230.  
  231.     /* UnlockMsgQueue(struct MsgQueue *Queue):
  232.      *
  233.      *    Wake up all tasks waiting for the queue to become
  234.      *    smaller. Note: this will change the maximum queue
  235.      *    size.
  236.      */
  237.  
  238. VOID __regargs
  239. UnlockMsgQueue(struct MsgQueue *Queue)
  240. {
  241.         // Valid data?
  242.  
  243.     if(Queue)
  244.     {
  245.         struct SemaphoreRequest *WaitRequest;
  246.  
  247.             // Gain access to the handle
  248.  
  249.         ObtainSemaphore(&Queue -> Access);
  250.  
  251.             // Notify all waiting tasks
  252.  
  253.         for(WaitRequest = (struct SemaphoreRequest *)Queue -> WaitList . mlh_Head ; WaitRequest -> sr_Link . mln_Succ ; WaitRequest = (struct SemaphoreRequest *)WaitRequest -> sr_Link . mln_Succ)
  254.             Signal(WaitRequest -> sr_Waiter,SIGF_SINGLE);
  255.  
  256.             // Reset the maximum queue size
  257.  
  258.         Queue -> MaxSize = 0;
  259.  
  260.             // Drop the semaphore
  261.  
  262.         ReleaseSemaphore(&Queue -> Access);
  263.     }
  264. }
  265.  
  266.     /* DeleteMsgQueue(struct MsgQueue *Queue):
  267.      *
  268.      *    Free a queue handle.
  269.      */
  270.  
  271. VOID __regargs
  272. DeleteMsgQueue(struct MsgQueue *Queue)
  273. {
  274.         // Valid data?
  275.  
  276.     if(Queue)
  277.     {
  278.         struct MsgItem *Item,*Next;
  279.  
  280.             // Make sure no tasks is waiting in the list
  281.  
  282.         UnlockMsgQueue(Queue);
  283.  
  284.             // Disable multitasking
  285.  
  286.         Forbid();
  287.  
  288.             // Clear the queue signal
  289.  
  290.         ClrSignal(Queue -> SigMask);
  291.  
  292.             // Wait until all tasks are finished
  293.  
  294.         while(Queue -> QueueSize)
  295.             Wait(Queue -> SigMask);
  296.  
  297.             // Reenable multitasking
  298.  
  299.         Permit();
  300.  
  301.             // Remove each item from the list
  302.  
  303.         for(Item = (struct MsgItem *)Queue -> MsgList . mlh_Head ; Next = (struct MsgItem *)Item -> Link . mln_Succ ; Item = Next)
  304.             DeleteMsgItem(Item);
  305.  
  306.             // Free the signal bit if necessary
  307.  
  308.         if(Queue -> SigBit != -1)
  309.             FreeSignal(Queue -> SigBit);
  310.  
  311.             // Free the handle
  312.  
  313.         FreeVecPooled(Queue);
  314.     }
  315. }
  316.  
  317.     /* CreateMsgQueue(ULONG SigMask,LONG MaxSize):
  318.      *
  319.      *    Allocate a queue handle.
  320.      */
  321.  
  322. struct MsgQueue * __regargs
  323. CreateMsgQueue(ULONG SigMask,LONG MaxSize)
  324. {
  325.     struct MsgQueue    *Queue;
  326.  
  327.         // Allocate the queue handle
  328.  
  329.     if(Queue = (struct MsgQueue *)AllocVecPooled(sizeof(struct MsgQueue),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR))
  330.     {
  331.             // Initialize the access semaphore
  332.  
  333.         InitSemaphore(&Queue -> Access);
  334.  
  335.             // Initialize the message item list
  336.  
  337.         NewList((struct List *)&Queue -> MsgList);
  338.  
  339.             // Reset the size data
  340.  
  341.         Queue -> QueueSize    = 0;
  342.         Queue -> MaxSize    = MaxSize;
  343.  
  344.             // Initialize the queue wait list
  345.  
  346.         NewList((struct List *)&Queue -> WaitList);
  347.  
  348.             // Store the owner address
  349.  
  350.         Queue -> SigTask = FindTask(NULL);
  351.  
  352.             // Do we have a signal mask ready?
  353.  
  354.         if(SigMask)
  355.         {
  356.                 // Use it
  357.  
  358.             Queue -> SigMask    = SigMask;
  359.             Queue -> SigBit        = -1;
  360.         }
  361.         else
  362.         {
  363.                 // Allocate a new signal
  364.  
  365.             if((Queue -> SigBit = AllocSignal(-1)) == -1)
  366.             {
  367.                 FreeVecPooled(Queue);
  368.  
  369.                 return(NULL);
  370.             }
  371.             else
  372.                 Queue -> SigMask = (1L << Queue -> SigBit);
  373.         }
  374.     }
  375.  
  376.     return(Queue);
  377. }
  378.  
  379.     /* SetQueueDiscard(struct MsgQueue *Queue,BOOL Mode):
  380.      *
  381.      *    Set whether new items should be added to the
  382.      *    queue or whether they should rather get
  383.      *    discarded instead.
  384.      */
  385.  
  386. VOID __regargs
  387. SetQueueDiscard(struct MsgQueue *Queue,BOOL Mode)
  388. {
  389.     if(Queue)
  390.     {
  391.         ObtainSemaphore(&Queue -> Access);
  392.  
  393.         Queue -> Discard = Mode;
  394.  
  395.         ReleaseSemaphore(&Queue -> Access);
  396.     }
  397. }
  398.